// 除非遵守许可证，否则不得使用此文件。
// 您可以通过
// 
// www.apache.org/licenses/LICENSE-2.0 
// 
// 除非适用法律要求或书面同意，否则根据许可证分发的软件
// 按“原样”分发，
// 无任何明示或暗示的保证或条件。
// 请参阅许可证，了解管理许可的特定语言和
// 许可证下的限制。

package version

import (
	"context"

	"github.com/coreos/go-semver/semver"
	"go.uber.org/zap"
)

// 管理器包含管理etcd群集版本降级过程的逻辑。
type Manager struct {
	lg *zap.Logger
	s  Server
}

// NewManager返回一个新的管理器实例
func NewManager(lg *zap.Logger, s Server) *Manager {
	return &Manager{
		lg: lg,
		s:  s,
	}
}

// 降级验证集群是否可下载到提供的目标版本，如果不能下载，则返回错误。
func (m *Manager) DowngradeValidate(ctx context.Context, targetVersion *semver.Version) error {
	// 获取领导者提交索引并等待本地存储完成应用该索引
	// 以避免使用过时的降级信息
	err := m.s.LinearizableReadNotify(ctx)
	if err != nil {
		return err
	}
	cv := m.s.GetClusterVersion()
	allowedTargetVersion := allowedDowngradeVersion(cv)
	if !targetVersion.Equal(*allowedTargetVersion) {
		return ErrInvalidDowngradeTargetVersion
	}

	downgradeInfo := m.s.GetDowngradeInfo()
	if downgradeInfo != nil && downgradeInfo.Enabled {
		// Todo:返回降级状态以及错误消息
		return ErrDowngradeInProcess
	}
	return nil
}

// 降级启用启动etcd群集版本降级过程。
func (m *Manager) DowngradeEnable(ctx context.Context, targetVersion *semver.Version) error {
	// 开始降级前验证降级功能
	err := m.DowngradeValidate(ctx, targetVersion)
	if err != nil {
		return err
	}
	return m.s.DowngradeEnable(context.Background(), targetVersion)
}

// 降级取消取消正在进行的降级过程。
func (m *Manager) DowngradeCancel(ctx context.Context) error {
	err := m.s.LinearizableReadNotify(ctx)
	if err != nil {
		return err
	}
	downgradeInfo := m.s.GetDowngradeInfo()
	if !downgradeInfo.Enabled {
		return ErrNoInflightDowngrade
	}
	return m.s.DowngradeCancel(ctx)
}
